require_relative './parser/parser'

module Stone
  ASTLeaf = Y::ASTLeaf
  ASTList = Y::ASTList 

  ### Leaf ###
  class NumberLiteray < ASTLeaf
    def value
      token.value
    end
  end

  class Name < ASTLeaf
    def value
      token.value
    end
  end

  class StringLiteray < ASTLeaf
  end

  class Simple < ASTLeaf
  end

  ### List ###
  class BlockStmnt < ASTList
    singleton_class.undef_method :create
  end

  class IfStmnt < ASTList
    singleton_class.undef_method :create

    def cond
      children[0]
    end

    def then_block
      children[1]
    end
    
    def else_block
      num > 2 ? children[2] : nil
    end

    def to_s
      "(if #{cond.to_s} then #{then_block.to_s} else #{else_block.to_s})"
    end
  end

  class WhileStmnt < ASTList
    singleton_class.undef_method :create
    def cond  = children[0]
    def block = children[1]
    def to_s  = "(while #{cond.to_s} #{block.to_s})"
  end

  class NegExpr < ASTList
    singleton_class.undef_method :create

    def oprand
      children[0]
    end

    def to_s
      "(-#{oprand})"
    end
  end

  class PrimaryExpr < ASTList
    def oprand
      children.first
    end

    def postfix(nest)
      children[num-nest-1]
    end

    def postfix?(nest)
      num - nest > 1
    end

    def self.create(c)
      c.size == 1 ? c.first : PrimaryExpr.new(c)
    end
  end

  class BinaryExpr < ASTList
    def left
      children[0]
    end

    def op
      children[1].token.value
    end

    def right
      children[2]
    end
  end

  class NullStmnt < ASTList
    singleton_class.undef_method :create
  end

  class FnStmnt < ASTList
    singleton_class.undef_method :create
    
    def name
      children
        .first.token.value.to_s
    end

    def params
      children[1] 
    end

    def body
      children[2]
    end

    def to_s 
      "(fn #{name} #{params} #{body})"
    end
  end

  class ParameterList < ASTList 
    singleton_class.undef_method :create

    def name(o) 
      children[o].token.value.to_s
    end
  end


  class Postfix < ASTList 
    singleton_class.undef_method :create
  end

  class Arguments < Postfix
  end
end

